/*
* CSP-201412P4 最优灌溉（图、最小生成树、Prim算法、优先队列）
* 麦田看作点，水渠看作边，建设费用是边权。
* 灌溉所有麦田所需要的最小费用就是求最小生成树。
* 因Kruskal算法用到并查集，计划过几天再练。我们先用Prim算法解。
*/
import java.io.PrintWriter;
import java.util.*;

class Edge implements Comparable<Edge> {
  public int u, v, w; // 源点（编号，可索引邻接链表）, 端点, 权值

  public Edge() {
    u = v = w = 0;
  }

  public Edge(int tu, int tv, int tw) {
    u = tu;
    v = tv;
    w = tw;
  }

  @Override
  public int compareTo(Edge o) { // 按权值比较，用来支持优先队列
    return this.w - o.w;
  }
}

class Graph {
  final int V, E; // 点数、边数
  ArrayList<LinkedList<Edge>> g; // 邻接链表

  Graph(int nv, int ne, Scanner s) {
    V = nv;
    E = ne;
    g = new ArrayList<LinkedList<Edge>>(V + 1); // 编号从1开始，多加1个。
    g.add(new LinkedList<Edge>()); // 加个[0]但不用
    for (int i = 1; i <= V; ++i) {
      g.add(new LinkedList<Edge>()); // 初始化V个空链表
    }
    for (int i = 0; i < E; ++i) {
      int u = s.nextInt(), v = s.nextInt(), w = s.nextInt(); // 水渠连通u~v，花费w
      g.get(u).add(new Edge(u, v, w));
      g.get(v).add(new Edge(v, u, w)); // 双向连通，加入反向边
    }
  }

  public int prim() {
    boolean[] reached = new boolean[V + 1]; // [v]=true表示已在生成树中
    PriorityQueue<Edge> pq = new PriorityQueue<Edge>(); // 优先队列，根据边权排序
    for (Edge e : g.get(1)) { // 从点1开始（起点可任选，最终MST形态可能不同）
      pq.add(e); // 把关联边都入队
    }
    reached[1] = true; // 点1已上树
    int fee = 0; // 最多10万边 * 1万花费 ~= 10亿，不超int32范围
    while (!pq.isEmpty()) {
      Edge e = pq.poll();
      if (reached[e.v]) { // 边e的端点已通，不是横切边。
        continue;
      }
      reached[e.v] = true; // 连通了新点e.v
      fee += e.w; // 记入最小生成树的总花费
      for (Edge f : g.get(e.v)) { // 检查点v关联的边
        if (!reached[f.v]) { // 边f端点不在MST中，入队
          pq.add(f);
        }
      }
    }
    return fee;
  }
}

public class Main {
  public static void main(String[] args) {
    Scanner s = new Scanner(System.in);
    final int n = s.nextInt(), m = s.nextInt(); // 点数、边数
    Graph g = new Graph(n, m, s);
    System.out.println(g.prim());
  }
}
